/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.admin.service.impl;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.dto.cert.CertClassificationSubmitDTO;
import org.springblade.modules.admin.entity.CertClassification;
import org.springblade.modules.admin.entity.CertWork;
import org.springblade.modules.admin.entity.UserCert;
import org.springblade.modules.admin.service.ICertWorkService;
import org.springblade.modules.admin.service.UserCertService;
import org.springblade.modules.admin.vo.CertClassificationVO;
import org.springblade.modules.admin.mapper.CertClassificationMapper;
import org.springblade.modules.admin.service.ICertClassificationService;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.modules.admin.vo.cert.CertClassificationDetailVO;
import org.springblade.modules.admin.vo.cert.CertClassificationWorkVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 证件类别表 服务实现类
 *
 * @author ysq
 * @since 2024-03-29
 */
@Service
public class CertClassificationServiceImpl extends BaseServiceImpl<CertClassificationMapper, CertClassification> implements ICertClassificationService {

	@Autowired
	private ICertWorkService certWorkService;
	@Lazy
	@Autowired
	private UserCertService userCertService;

	@Override
	public IPage<CertClassificationVO> selectCertClassificationPage(IPage<CertClassificationVO> page, CertClassificationVO certClassification) {
		return page.setRecords(baseMapper.selectCertClassificationPage(page, certClassification));
	}

	@Override
	public CertClassificationDetailVO detail(Long id) {
		CertClassificationDetailVO detail = new CertClassificationDetailVO();
		CertClassification certClassification = getById(id);
		if (certClassification == null) {
			throw new ServiceException("未找到对应信息!");
		}

		BeanUtil.copyProperties(certClassification, detail);
		List<CertWork> certWorkList = certWorkService.list(Wrappers.<CertWork>lambdaQuery().eq(CertWork :: getCertClassificationId, id));
		detail.setCertWorkList(certWorkList);
		return detail;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public boolean submit(CertClassificationSubmitDTO certClassificationSubmit) {
		if (!checkCertClassName(certClassificationSubmit.getId(), certClassificationSubmit.getName())) {
			throw new ServiceException("列表已存在相同的证件类型名称!");
		}
		long contentCount = certClassificationSubmit.getCertWorkList().stream().map(CertWork :: getContent).distinct().count();
		if (certClassificationSubmit.getCertWorkList().size() != (int) contentCount) {
			throw new ServiceException("作业项目存在重复输入!");
		}

		List<CertWork> saveOrUpdateCertWorkList = new ArrayList<>(4);
		List<Long> removeContentIdList = new ArrayList<>(4);
		CertClassification certClassification = null;
		if (certClassificationSubmit.getId() == null) {
			certClassification = new CertClassification();
			saveOrUpdateCertWorkList.addAll(certClassificationSubmit.getCertWorkList());
		} else {
			certClassification = getById(certClassificationSubmit.getId());
			if (certClassification == null) {
				throw new ServiceException("操作数据异常!");
			}
			// 旧的作业项目数据
			List<CertWork> oldCertWorkList = certWorkService.list(Wrappers.<CertWork>lambdaQuery().eq(CertWork :: getCertClassificationId, certClassification.getId()));
			List<Long> oldWorkIds = oldCertWorkList.stream().map(CertWork::getId).collect(Collectors.toList());
			// 新的作业项目数据
			List<CertWork> newCertWorkList = certClassificationSubmit.getCertWorkList();
			List<Long> newWorkIds = newCertWorkList.stream().map(CertWork::getId).filter(Objects::nonNull).collect(Collectors.toList());

			// 新数据与旧数据相互差集，即可分别得出新增和删除集合
			List<CertWork> addContentList = newCertWorkList.stream().filter(t -> !oldWorkIds.contains(t.getId())).collect(Collectors.toList());
			removeContentIdList = oldCertWorkList.stream().map(CertWork :: getId).filter(id -> !newWorkIds.contains(id)).collect(Collectors.toList());
			saveOrUpdateCertWorkList.addAll(addContentList);

			// 旧数据与新数据取交集，即可得出存量数据更新
			List<CertWork> updateContentList = newCertWorkList.stream().filter(t -> oldWorkIds.contains(t.getId())).collect(Collectors.toList());
			saveOrUpdateCertWorkList.addAll(updateContentList);
		}

		if (Func.isNotEmpty(removeContentIdList)) {
			int checkCount = userCertService.count(Wrappers.<UserCert>lambdaQuery().eq(UserCert :: getCertType, certClassification.getId()).in(UserCert :: getWorkPro, removeContentIdList));
			if (checkCount > 0) {
				throw new ServiceException("存在有作业项目已被证件使用，不能删除!");
			}
		}

		BeanUtil.copyProperties(certClassificationSubmit, certClassification);
		if (saveOrUpdate(certClassification)) {
			for (CertWork certWork : saveOrUpdateCertWorkList) {
				certWork.setCertClassificationId(certClassification.getId());
			}
		}

		return ( saveOrUpdateCertWorkList.isEmpty() || certWorkService.saveOrUpdateBatch(saveOrUpdateCertWorkList) )
				&& ( removeContentIdList.isEmpty() || certWorkService.removeByIds(removeContentIdList) );
	}

	/**
	 * 检验证件分类名称重复
	 * @param id
	 * @param name
	 * @return
	 */
	private boolean checkCertClassName(Long id, String name) {
		LambdaQueryWrapper<CertClassification> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		if (id != null) {
			lambdaQueryWrapper.ne(CertClassification :: getId, id);
		}
		lambdaQueryWrapper.eq(CertClassification :: getName, name);
		return count(lambdaQueryWrapper) <= 0;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public boolean deleteByIds(List<Long> ids) {
		int checkDel = userCertService.count(Wrappers.<UserCert>lambdaQuery().in(UserCert :: getCertType, ids));
		if (checkDel > 0) {
			throw new ServiceException("请删除证件类型下的证件!");
		}

		// 删除证件类型下绑定的作业项目
		List<CertWork> certWorkList = certWorkService.list(Wrappers.<CertWork>lambdaQuery().in(CertWork :: getCertClassificationId, ids));
		List<Long> certWorkIds = certWorkList.stream().map(CertWork :: getId).collect(Collectors.toList());

		return deleteLogic(ids) && certWorkIds.isEmpty() || certWorkService.deleteLogic(certWorkIds);
	}

	@Override
	public boolean delWorkCheck(Long certClassificationId, Long certWorkId) {
		int checkCount = userCertService.count(Wrappers.<UserCert>lambdaQuery().eq(UserCert::getCertType, certClassificationId).in(UserCert::getWorkPro, certWorkId));
		return checkCount <= 0;

	}

	@Override
	public List<Map<String, Object>> workSelect(List<Long> certClassificationIds) {
		List<CertWork> list = null;
		if (Func.isNotEmpty(certClassificationIds)) {
			list = certWorkService.list(Wrappers.<CertWork>lambdaQuery().in(CertWork :: getCertClassificationId, certClassificationIds));
		} else {
			list = certWorkService.list();
		}

        return list.stream().map(certClassification -> {
			Map<String, Object> map = new HashMap<>(2);
			map.put("key", certClassification.getId());
			map.put("value", certClassification.getContent());
			return map;
		}).collect(Collectors.toList());
	}

	@Override
	public List<CertClassificationWorkVO> selectCertTypeAndWorks(String name, String content) {
		return baseMapper.selectCertTypeAndWorks(name, content);
	}
}
